// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once

#include <pollux/common/base/class_name.h>
#include <pollux/common/base/exceptions.h>
#include <pollux/type/type.h>

namespace kumo::pollux::core {
    class IExpr;
    using ExprPtr = std::shared_ptr<const IExpr>;

    /// An implicitly-typed expression, such as function call, literal, etc.
    class IExpr {
    public:
        explicit IExpr(std::optional<std::string> alias = std::nullopt)
            : alias_{std::move(alias)} {
        }

        virtual const std::vector<std::shared_ptr<const IExpr> > &getInputs()
        const = 0;

        std::shared_ptr<const IExpr> getInput() const {
            return getInputs().size() == 1 ? getInputs().at(0) : nullptr;
        }

        virtual ~IExpr() = default;

        virtual std::string toString() const = 0;

        const std::optional<std::string> &alias() const {
            return alias_;
        }

    protected:
        static const std::vector<std::shared_ptr<const IExpr> > &EMPTY() {
            static const std::vector<std::shared_ptr<const IExpr> > empty{};
            return empty;
        }

        std::string appendAliasIfExists(std::string s) const {
            if (!alias_.has_value()) {
                return s;
            }

            return fmt::format("{} AS {}", std::move(s), alias_.value());
        }

        std::optional<std::string> alias_;
    };
} // namespace kumo::pollux::core
